home *** CD-ROM | disk | FTP | other *** search
- // ---------- parody.c++
-
- // ==========================================
- // Parody persistent object member functions
- // ==========================================
-
- #include <new.h>
- #include <stdlib.h>
- #include "parody.h"
- char *getenv(), *home;
-
- void NoMemory()
- {
- exit(-1);
- }
-
- // =======================================
- // Parody member functions
- // =======================================
-
- // ---------- construct a Parody database
- Parody::Parody(pString name) :
- FileHeader( name + pString(".DAT")),
- index(name + pString(".NDX"))
- {
- set_new_handler(NoMemory);
- rebuildnode = 0;
- }
-
- // ---------- close the Parody database
- Parody::~Parody()
- {
- Btree *bt = (Btree *) btrees.FirstListEntry();
- while (bt != NULL) {
- delete bt;
- bt = (Btree *) btrees.FirstListEntry();
- }
-
- }
-
- void Parody::Flush()
- {
- Parody::~Parody();
- FileHeader::Flush();
- index.Flush();
- }
-
- // ------- read an object header record
- void Parody::GetObjectHeader(
- ObjAddr nd,ObjectHeader &objhdr)
- {
- Node *node = new Node(this, nd);
- nfile.read((char *)&objhdr, sizeof(ObjectHeader));
- delete node;
- }
-
- void Parody::RebuildIndexes(ObjAddr nd)
- {
- rebuildnode = nd;
- }
-
- // =======================================
- // Persistent base class member functions
- // =======================================
-
- Persistent *Persistent::thispers = NULL;
-
- // ------ constructor
- Persistent::Persistent(Parody& db, int cid) :
- parody(db), objhdr(cid)
- {
- oldthispers = thispers;
- thispers = this;
- changed = pFalse;
- deleted = pFalse;
- newobject = pFalse;
- offset = 0;
- indexcount = 0;
- count = 0;
- node = NULL;
- objectlist = NULL;
- objectcopy = NULL;
- objectaddress = 0;
- }
-
- // ------ destructor
- Persistent::~Persistent()
- {
- RemoveObject();
- }
-
- // ------ search the collected Btrees for this key's index
- // add it if it does not exist
- Btree *Persistent::FindIndex(Key *key)
- {
- Btree *bt = NULL;
- if (key == NULL)
- key = (Key *) keys.FirstListEntry();
- if (key != NULL) {
- bt = (Btree *) parody.Btrees().FirstListEntry();
- while (bt != NULL) {
- Key *tkey = bt->NullKey();
- if (tkey->classid == key->classid &&
- tkey->indexno == key->indexno)
- break;
- bt = (Btree *) (bt->NextListEntry());
- }
- if (bt == NULL) {
- // --- key does not have declared Btree index yet
- bt = new Btree(parody.IndexFile(), key);
- bt->AppendListEntry(&parody.Btrees());
- }
- }
- return bt;
- }
-
- // ---------------- record the object's state
- void Persistent::RecordObject()
- {
- // ---- remove this obj in case it was recorded already
- RemoveObject();
- // ---- put the object's address in a parody list of
- // instantiated objects
- objectlist = new ObjectList(&parody.Objects(), this);
- // ---- make copies of the original keys for later update
- Key *key = (Key *) keys.FirstListEntry();
- while (key != NULL) {
- Key *ky = key->Make();
- *ky = *key;
- ky->Key::operator=(*key);
- ky->AppendListEntry(&orgkeys);
- // --- instantiate the index b-tree (if not already)
- FindIndex(ky);
- key = (Key *) (key->NextListEntry());
- }
- }
-
- // ---- remove the record of the object's state
- void Persistent::RemoveObject()
- {
- // --- remove object's address from the parody list
- delete objectlist;
- objectlist = NULL;
- // ----- remove copies of the original keys
- Key *ky = (Key *) orgkeys.FirstListEntry();
- while (ky != NULL) {
- delete ky;
- ky = (Key *) orgkeys.FirstListEntry();
- }
- }
-
- // -- called from derived constructor after all construction
- void Persistent::LoadObject(ObjAddr nd)
- {
- thispers = NULL;
- objectaddress = nd;
- if (parody.RebuildingIndexes())
- objectaddress = parody.RebuildNode();
- if (objectaddress == 0)
- // --- position at object's node
- SearchIndex((Key *) keys.FirstListEntry());
- if (objectaddress != 0) {
- // --- search for a previous instance of this object
- ObjectList *obj =
- (ObjectList *) parody.Objects().FirstListEntry();
- while (obj != NULL) {
- if (objectaddress == obj->object->objectaddress) {
- // ---- object already instantiated
- objectcopy = obj->object;
- break;
- }
- obj = (ObjectList *) obj->NextListEntry();
- }
- if (obj == NULL) {
- PositionNode();
- ReadDataMembers();
- }
- }
- thispers = oldthispers;
- }
-
- // ------ write the object to the database
- void Persistent::ObjectOut()
- {
- // --- tell object to write its data members
- Write();
- // --- pad the last node
- int padding = nodedatalength - offset;
- if (padding) {
- pString pads(padding);
- parody.Nfile().write(pads, padding);
- }
- NodeNbr nx = node->NextNode();
- node->SetNextNode(0);
- delete node;
- node = NULL;
- // --- if node was linked, object got shorter
- while (nx != 0) {
- Node nd(&parody, nx);
- nx = nd.NextNode();
- nd.MarkNodeDeleted();
- }
- }
-
- // ----- write the object's node header
- void Persistent::WriteObjectHeader()
- {
- // --- write the relative node number and class id
- fstream& df = parody.Nfile();
- df.write((char *) &objhdr, sizeof(ObjectHeader));
- offset = sizeof(ObjectHeader);
- objhdr.ndnbr++;
- }
-
- // ----- write the object's node header
- void Persistent::ReadObjectHeader()
- {
- // --- write the relative node number and class id
- fstream& df = parody.Nfile();
- df.read((char *) &objhdr, sizeof(ObjectHeader));
- offset = sizeof(ObjectHeader);
- }
-
- // --- called from derived destructor before all destruction
- // a new or existing object is being saved
- void Persistent::SaveObject()
- {
- if (parody.RebuildingIndexes())
- AddIndexes();
- else if (newobject) {
- if (!deleted && ObjectExists()) {
- PositionNode();
- AddIndexes();
- ObjectOut();
- RecordObject();
- }
- }
- else if (deleted || changed) {
- if (!ObjectExists())
- return;
- // --- position the parody file at the object's node
- PositionNode();
- if (deleted) {
- // --- delete the object's nodes from the database
- while (node != NULL) {
- node->MarkNodeDeleted();
- NodeNbr nx = node->NextNode();
- delete node;
- if (nx)
- node = new Node(&parody, nx);
- else
- node = NULL;
- }
- DeleteIndexes();
- }
- else {
- // --- tell object to write its data members
- ObjectOut();
- // ---- update the object's indexes
- UpdateIndexes();
- RecordObject();
- }
- }
- }
-
- // --- read one data member of the object from the database
- void Persistent::ReadObject(void *buf, int length)
- {
- fstream& df = parody.Nfile();
- while (node != NULL && length > 0) {
- if (offset == nodedatalength) {
- NodeNbr nx = node->NextNode();
- delete node;
- node = nx ? new Node(&parody, nx) : NULL;
- ReadObjectHeader();
- }
- if (node != NULL) {
- int len = min(length, nodedatalength-offset);
- df.read((char *)buf, len);
- buf = (char *)buf + len;
- offset += len;
- length -= len;
- }
- }
- }
-
- // --- write one data member of the object to the database
- void Persistent::WriteObject(void *buf, int length)
- {
- fstream& df = parody.Nfile();
- while (node != NULL && length > 0) {
- if (offset == nodedatalength) {
- NodeNbr nx = node->NextNode();
- if (nx == 0)
- nx = parody.NewNode();
- node->SetNextNode(nx);
- delete node;
- node = new Node(&parody, nx);
- WriteObjectHeader();
- }
- int len = min(length, nodedatalength-offset);
- df.write((char *)buf, len);
- buf = (char *)buf + len;
- offset += len;
- length -= len;
- }
- }
-
- // ------------ read a string
- void Persistent::ReadObject(pString& str)
- {
- int len;
- ReadObject(&len, sizeof(int));
- pString s(len);
- ReadObject((char *)s, len);
- str = s;
- }
-
- // ------------ write a string
- void Persistent::WriteObject(pString& str)
- {
- int len = str.Strlen();
- WriteObject(&len, sizeof(int));
- WriteObject((char *)str, len);
- }
-
- // ---- add the index values to the object's index btrees
- void Persistent::AddIndexes()
- {
- Key *key = (Key *) keys.FirstListEntry();
- while (key != NULL) {
- Btree *bt = FindIndex(key);
- key->fileaddr = objectaddress;
- bt->Insert(key);
- key = (Key *) (key->NextListEntry());
- }
- }
-
- // ---- update the index values in the object's index btrees
- void Persistent::UpdateIndexes()
- {
- Key *oky = (Key *) orgkeys.FirstListEntry();
- Key *key = (Key *) keys.FirstListEntry();
- while (key != NULL) {
- if (!(*oky == *key)) {
- // --- key value has changed, update the index
- // --- delete the old
- Btree *bt = FindIndex(oky);
- oky->fileaddr = objectaddress;
- bt->Delete(oky);
- // --- insert the new
- key->fileaddr = objectaddress;
- bt->Insert(key);
- }
- oky = (Key *) (oky->NextListEntry());
- key = (Key *) (key->NextListEntry());
- }
- }
-
- // -- delete the index values from the object's index btrees
- void Persistent::DeleteIndexes()
- {
- Key *key = (Key *) orgkeys.FirstListEntry();
- while (key != NULL) {
- Btree *bt = FindIndex(key);
- key->fileaddr = objectaddress;
- bt->Delete(key);
- key = (Key *) (key->NextListEntry());
- }
- }
-
- // ----- position the file to the specifed node number
- void Persistent::PositionNode()
- {
- if (objectaddress) {
- node = new Node(&parody, (NodeNbr) objectaddress);
- offset = sizeof(ObjectHeader);
- fstream& nf = parody.Nfile();
- ObjectHeader oh;
- nf.read((char *)&oh, sizeof(ObjectHeader));
- nf.seekp(nf.tellg());
- if (oh.classid != objhdr.classid || oh.ndnbr != 0)
- objectaddress = 0;
- }
- }
-
- // ------- search the index for a match on the key
- void Persistent::SearchIndex(Key *key)
- {
- objectaddress = 0;
- if (key != NULL && !key->isNullValue()) {
- Btree *bt = FindIndex(key);
- if (bt != NULL && bt->Find(key)) {
- if (key->indexno != 0) {
- Key *bc;
- do
- bc = bt->Previous();
- while (bc != NULL && *bc == *key);
- key = bt->Next();
- }
- objectaddress = key->fileaddr;
- }
- }
- }
-
- // --------- find an object by a key value
- void Persistent::FindObject(Key *key)
- {
- SearchIndex(key);
- PositionNode();
- ReadDataMembers();
- }
-
- // --- scan nodes forward to the first one of next object
- void Persistent::ScanForward(NodeNbr nd)
- {
- ObjectHeader oh;
- while (++nd < parody.HighestNode()) {
- parody.GetObjectHeader(nd, oh);
- if (oh.classid == objhdr.classid && oh.ndnbr == 0) {
- objectaddress = nd;
- break;
- }
- }
- }
-
- // --- scan nodes back to first one of the previous object
- void Persistent::ScanBackward(NodeNbr nd)
- {
- ObjectHeader oh;
- while (--nd > 0) {
- parody.GetObjectHeader(nd, oh);
- if (oh.classid == objhdr.classid && oh.ndnbr == 0) {
- objectaddress = nd;
- break;
- }
- }
- }
-
- // --- retrieve the first object in a key sequence
- void Persistent::FirstObject(Key *key)
- {
- objectaddress = 0;
- Btree *bt = FindIndex(key);
- if (bt == NULL)
- // ----- keyless object
- ScanForward(0);
- else if ((key = bt->First()) != NULL)
- objectaddress = key->fileaddr;
- if (objectaddress != 0) {
- PositionNode();
- ReadDataMembers();
- }
- }
-
- // --- retrieve the last object in a key sequence
- void Persistent::LastObject(Key *key)
- {
- objectaddress = 0;
- Btree *bt = FindIndex(key);
- if (bt == NULL)
- // ----- keyless object
- ScanBackward(parody.HighestNode());
- else if ((key = bt->Last()) != NULL)
- objectaddress = key->fileaddr;
- if (objectaddress != 0) {
- PositionNode();
- ReadDataMembers();
- }
- }
-
- // --- retrieve the next object in a key sequence
- void Persistent::NextObject(Key *key)
- {
- ObjAddr oa = objectaddress;
- objectaddress = 0;
- Btree *bt = FindIndex(key);
- if (bt == NULL)
- // ----- keyless object
- ScanForward(oa);
- else if ((key = bt->Next()) != NULL)
- objectaddress = key->fileaddr;
- if (objectaddress != 0) {
- PositionNode();
- ReadDataMembers();
- }
- }
-
- //UMESH
- // read in the current object
- void Persistent::CurrentObject(Key *key)
- {
- ObjAddr oa = objectaddress;
- objectaddress = 0;
- Btree *bt = FindIndex(key);
- if (bt == NULL)
- // ----- keyless object
- ScanForward(oa);
- else if ((key = bt->Current()) != NULL)
- objectaddress = key->fileaddr;
- if (objectaddress != 0) {
- PositionNode();
- ReadDataMembers();
- }
- }
-
- // --- retrieve the previous object in a key sequence
- void Persistent::PreviousObject(Key *key)
- {
- ObjAddr oa = objectaddress;
- objectaddress = 0;
- Btree *bt = FindIndex(key);
- if (bt == NULL)
- // ----- keyless object
- ScanBackward(oa);
- else if ((key = bt->Previous()) != NULL)
- objectaddress = key->fileaddr;
- if (objectaddress != 0) {
- PositionNode();
- ReadDataMembers();
- }
- }
-
- // ------- read an object's data members
- void Persistent::ReadDataMembers()
- {
- if (objectaddress != 0) {
- // --- tell object to read its data members
- Read();
- delete node;
- node = NULL;
- // --- put the secondary keys into the table
- RecordObject();
- }
- }
-
- // -------- add an object to the Parody database
- pBool Persistent::AddObject()
- {
- newobject =
- (pBool) (objectaddress == 0 && TestRelationships());
- if (newobject) {
- delete node; // (just in case)
- node = new Node(&parody, parody.NewNode());
- objectaddress = node->GetNodeNbr();
- WriteObjectHeader();
- }
- return newobject;
- }
-
- // ---------- mark a persistent object for change
- pBool Persistent::ChangeObject()
- {
- changed = TestRelationships();
- return changed;
- }
-
- // ---------- mark a persistent object for delete
- pBool Persistent::DeleteObject()
- {
- Key *key = (Key *) keys.FirstListEntry();
-
- if ( key ) {
-
- Key *ky = key->Make();
- *ky = *key;
- ky->Key::operator=(*key);
-
- if (!ky->isNullValue()) {
- // --- scan for other objects related to this one
- Btree *bt = (Btree*) parody.Btrees().FirstListEntry();
- while (bt != NULL) {
- Key *tkey = bt->NullKey();
- if (tkey->relatedclass == ky->classid) {
- ky->Key::operator=(*tkey);
- if (bt->Find(ky) == pTrue) {
- // --- another object is related,
- // so the delete is rejected
- delete ky;
- return pFalse;
- }
- }
- bt = (Btree *) (bt->NextListEntry());
- }
- }
- delete ky;
- }
-
- deleted = pTrue;
- return deleted;
- }
-
- // ------ test an object's relationships
- // return false if it is related to a
- // nonexistent object
- pBool Persistent::TestRelationships()
- {
- Key *key = (Key *) keys.FirstListEntry();
- while (key != NULL) {
- Key *ky = key->Make();
- *ky = *key;
- ky->Key::operator=(*key);
- if (!ky->isNullValue()) {
- if (ky->relatedclass != -1) {
- ky->indexno = 0;
- ky->classid = ky->relatedclass;
- ky->fileaddr = 0;
- Btree *bt = FindIndex(ky);
- if (bt->Find(ky) ==pFalse)
- break;
- }
- }
- delete ky;
- key = (Key *) (key->NextListEntry());
- }
- return (pBool) (key == NULL);
- }
-
- // =====================================
- // Handle class (Handle)
- // =====================================
- Handle::Handle(Handle& handle)
- {
- body = handle.body;
- body->count++;
- }
-
- Handle::~Handle()
- {
- if (--body->count == 0)
- delete body;
- }
-
- Handle& Handle::operator=(Handle& empl)
- {
- if (--body->count == 0)
- delete body;
- body = empl.body;
- body->count++;
- return *this;
- }
-
- void Handle::ConstructBody(Persistent *pbody)
- {
- if (pbody->objectcopy != NULL) {
- // --- LoadObject found another instantiated
- // copy of the object
- body = pbody->objectcopy;
- delete pbody;
- }
- else
- body = pbody;
- body->count++;
- }
-